package com.lizhen.core.function.crypto;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.*;
import java.security.KeyStore.ProtectionParameter;
import java.security.KeyStore.SecretKeyEntry;
import java.security.cert.CertificateException;
import java.util.Scanner;

/**
 * @author lizhen
 */
public class Crypto {

    /**
     * @author lizhen
     */
    public Crypto() {
    }

    /**
     * @author lizhen
     */
    public static void main(String[] args) {
        KeyStoreDEMO.main(null);
//        MessageDigestDemo.main(null);
//        KeyGeneratorDemo.main(null);
//        KeyPairGenertorDemo.main(null);
//        GenerateSignatureDemo.main(null);
//        VerifySignatureDemo.main(null);
//        CipherEncrypt.main(null);
//        CipherDecrypt.main(null);
    }

    static class KeyStoreDEMO {

        private static final String IN_CA_FILE_PATH = "H:\\JDK1.8\\jre\\lib\\security\\cacerts";
        private static final String OUT_CA_FILE_PATH = "1.8\\api\\main\\resource\\com\\lizhen\\core\\function\\crypto\\Crypto\\cacerts";

        public static void main(String args[]) {
            KeyStore keyStore = null;
            try {
                keyStore = KeyStore.getInstance("JCEKS");
                char[] password = "changeit".toCharArray();
                FileInputStream fis = new FileInputStream(IN_CA_FILE_PATH);
                keyStore.load(fis, password);
                ProtectionParameter protectionParam = new KeyStore.PasswordProtection(password);
                SecretKey secretKey = new SecretKeySpec("password".getBytes(), "DSA");
                SecretKeyEntry secretKeyEntry = new SecretKeyEntry(secretKey);
                keyStore.setEntry("secretKeyAlias", secretKeyEntry, protectionParam);
                FileOutputStream fos = new FileOutputStream(OUT_CA_FILE_PATH);
                keyStore.store(fos, password);
                SecretKeyEntry secretKeyEnt = (SecretKeyEntry) keyStore.getEntry("secretKeyAlias", protectionParam);
                SecretKey mysecretKey = secretKeyEnt.getSecretKey();

                System.out.println(keyStore);
                System.out.println("Algorithm used to generate key : " + mysecretKey.getAlgorithm());
                System.out.println("Format used for the key: " + mysecretKey.getFormat());
            } catch (KeyStoreException e) {
                e.printStackTrace();
            } catch (CertificateException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (UnrecoverableEntryException e) {
                e.printStackTrace();
            }
        }
    }

    static class MessageDigestDemo {
        public static void main(String args[]) {
            Scanner scanner = new Scanner(System.in);

            System.out.println("Enter the message");

            String message = scanner.nextLine();
            scanner.close();
            try {
                MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
                messageDigest.update(message.getBytes());
                byte[] digest = messageDigest.digest();
                StringBuffer hexString = new StringBuffer();
                for (int i = 0; i < digest.length; i++) {
                    hexString.append(Integer.toHexString(0xFF & digest[i]));
                }

                System.out.println(digest);
                System.out.println("Hex format : " + hexString.toString());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    }

    static class KeyGeneratorDemo {
        public static void main(String args[]) {
            try {
                KeyGenerator keyGen = KeyGenerator.getInstance("DES");
                SecureRandom secRandom = new SecureRandom();
                keyGen.init(secRandom);
                Key key = keyGen.generateKey();
                Mac mac = Mac.getInstance("HmacSHA256");
                mac.init(key);
                String msg = new String("Hi how are you");
                byte[] bytes = msg.getBytes();
                byte[] macResult = mac.doFinal(bytes);

                System.out.print("Mac result:");
                System.out.println(new String(macResult));
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
        }
    }

    static class KeyPairGenertorDemo {
        public static void main(String args[]) {
            try {
                KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DSA");
                keyPairGen.initialize(2048);
                KeyPair pair = keyPairGen.generateKeyPair();
                PrivateKey privKey = pair.getPrivate();
                PublicKey publicKey = pair.getPublic();

                System.out.println("privKey: " + privKey);
                System.out.println("publicKey: " + publicKey);
                System.out.println("Keys generated");
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
    }

    static class GenerateSignatureDemo {
        public static void main(String args[]) {
            Scanner scanner = new Scanner(System.in);

            System.out.println("Enter some text");

            String msg = scanner.nextLine();
            scanner.close();
            try {
                KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DSA");
                keyPairGen.initialize(2048);
                KeyPair pair = keyPairGen.generateKeyPair();
                PrivateKey privKey = pair.getPrivate();
                Signature sign = Signature.getInstance("SHA256withDSA");
                sign.initSign(privKey);
                byte[] bytes = msg.getBytes();
                sign.update(bytes);
                byte[] signature = sign.sign();

                System.out.println("Digital signature for given text: " + new String(signature, "UTF8"));
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (SignatureException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
        }
    }

    static class VerifySignatureDemo {
        public static void main(String args[]) {
            try {
                KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DSA");
                keyPairGen.initialize(2048);
                KeyPair pair = keyPairGen.generateKeyPair();
                PrivateKey privKey = pair.getPrivate();
                Signature sign = Signature.getInstance("SHA256withDSA");
                sign.initSign(privKey);
                byte[] bytes = "Hello how are you".getBytes();
                sign.update(bytes);
                byte[] signature = sign.sign();
                sign.initVerify(pair.getPublic());
                sign.update(bytes);
                boolean bool = sign.verify(signature);
                if (bool) {
                    System.out.println("Signature verified");
                } else {
                    System.out.println("Signature failed");
                }
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (SignatureException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
        }
    }

    static class CipherEncrypt {
        public static void main(String args[]) {
            try {
                KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
                keyPairGen.initialize(2048);
                KeyPair pair = keyPairGen.generateKeyPair();
                Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
                cipher.init(Cipher.ENCRYPT_MODE, pair.getPublic());
                byte[] input = "Welcome to lizhen".getBytes();
                cipher.update(input);
                byte[] cipherText = cipher.doFinal();

                System.out.println(new String(cipherText, "UTF8"));
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
    }

    static class CipherDecrypt {
        public static void main(String args[]) {
            try {
                KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
                keyPairGen.initialize(2048);
                KeyPair pair = keyPairGen.generateKeyPair();
                PublicKey publicKey = pair.getPublic();
                Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
                cipher.init(Cipher.ENCRYPT_MODE, publicKey);
                byte[] input = "Welcome to lizhen".getBytes();
                cipher.update(input);
                byte[] cipherText = cipher.doFinal();
                cipher.init(Cipher.DECRYPT_MODE, pair.getPrivate());
                byte[] decipheredText = cipher.doFinal(cipherText);

                System.out.println(new String(cipherText, "UTF8"));
                System.out.println(new String(decipheredText));
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                e.printStackTrace();
            } catch (BadPaddingException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
    }
}